﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Security;
using System.Collections;
using System.Net.Mail;

namespace CISExchangeDaemonService
{
    class Server
    {
        /// <summary>
        /// do pierwszej wersji, teraz juz nieprzydatne
        /// </summary>
        public const int MAX_ATTR_COUNT = 30;
        /// <summary>
        /// do zatrzymywania watku serwera
        /// </summary>
        private static bool IsServerRunning = true;
        /// <summary>
        /// adres IP, na ktorym zostanie odpalony serwer. Domyslnie brany z pliku .conf
        /// </summary>
        private static string IPaddress;
        /// <summary>
        /// numer portu, na ktorym dziala serwer
        /// </summary>
        private static int PortNumber;
        /// <summary>
        /// watek serwera
        /// </summary>
        private static Thread serverThread;
        /// <summary>
        /// glowne okno aplikacji (do pisania logu)
        /// </summary>

        private static TcpListener tcpListener;

        /// <summary>
        /// zatrzymuje serwer
        /// </summary>
        public static void StopServer()
        {
            IsServerRunning = false;
            TcpClient temp = new TcpClient();
            try
            {
                temp.Connect(IPAddress.Parse(IPaddress), PortNumber);
                temp.Close();
            }
            catch
            {
                return;
            }
            //żeby było bezpiecznie
            if (serverThread.ThreadState == ThreadState.Running) serverThread.Join(25000);
            try
            {
                tcpListener.Stop();
            }
            catch
            {

            }
        }

        /// <summary>
        /// rozpoczyna watek serwera
        /// </summary>
        /// <param name="ip">adres IP na ktorym serwer ma dzialac</param>
        /// <param name="port">numer portu, na ktorym ma dzialac serwer</param>
        public static void StartServerThread(string ip, int port)
        {
            IPaddress = ip;
            PortNumber = port;
            IsServerRunning = true;
            serverThread = new Thread(new ThreadStart(StartServer));
            serverThread.Start();
        }       

        /// <summary>
        /// Rozpoczyna dzialanie serwera. Przed uruchomieniem nalezy zainicjowac pola IPaddress i PortNumber
        /// </summary>
        private static void StartServer()
        {
            Manager.UpdateIndex();
            tcpListener = new TcpListener(IPAddress.Parse(IPaddress), PortNumber);
            try
            {
                tcpListener.Start();
            }
            catch
            {
                return;
            }
            while (IsServerRunning)
            {
                Socket socketForClient = tcpListener.AcceptSocket();
                if (!IsServerRunning) break;
                if (socketForClient.Connected)
                {
                    //bufor na odbierane dane
                    byte[] data_buffer = new byte[256];
                    byte[] ack = Encoding.UTF8.GetBytes("ack");
                    string attributes;
                    bool FINISHED_WITH_NO_ERRORS = true;

                    data_buffer = new byte[256];
                    socketForClient.Receive(data_buffer);
                    string operation_type = Encoding.UTF8.GetString(data_buffer).TrimEnd('\0');
                    socketForClient.Send(ack);

                    data_buffer = new byte[256];
                    socketForClient.Receive(data_buffer);
                    int char_count = int.Parse(Encoding.UTF8.GetString(data_buffer));
                    socketForClient.Send(ack);

                    data_buffer = new byte[char_count];
                    socketForClient.Receive(data_buffer);
                    attributes = Encoding.UTF8.GetString(data_buffer);
                    socketForClient.Send(ack);

                    if (FINISHED_WITH_NO_ERRORS)
                    {
                        Manager edm = new Manager();
                        string filename = edm.AppendDataToFile(operation_type,attributes);
                    }

                    socketForClient.Close();
                    string[] attrib = attributes.Split(';');
                    if (operation_type.Equals("add"))
                    {
                        SendMail(CISExchangeDaemon.Settings["FromMail"] as string, CISExchangeDaemon.Settings["ExchangeAdminMail"] as string, "Zalozenie konta dla: " + attrib[0] + " " + attrib[1], "Pojawily sie nowe dane do konta w ipj.gov.pl\nUzytkownik: " + attrib[1] + " " + attrib[2], false);
                    }
                    else if (operation_type.Equals("del"))
                    {
                        SendMail(CISExchangeDaemon.Settings["FromMail"] as string, CISExchangeDaemon.Settings["ExchangeAdminMail"] as string, "Usuniecie konta dla: " + attrib[0] + " " + attrib[1], "Prosba o usuniecie konta uzytkownika: " + attrib[1] + " " + attrib[2], false);
                    }
                }
            }
            tcpListener.Stop();
        }
        public static void StartUserManagerThread()
        {
            Thread umt = new Thread(new ThreadStart(ManageUser));
            umt.Start();
        }
        /// <summary>
        /// Rozpoczyna procedure dodawania/usuwania userow
        /// </summary>
        private static void ManageUser()
        {
            Manager edm = new Manager();
            string[] filenames = Directory.GetFiles(Directory.GetCurrentDirectory() + "\\pending\\");
            string mail = LoadMail("mail");
            foreach (string file in filenames)
            {
                string person = edm.LoadFromFile(file);
                string output;
                string[] temp = person.Split(';');
                StringBuilder sb = new StringBuilder();
                for (int i = 1; i < temp.Length; i++)
                {
                    sb.Append(temp[i] + ";");
                }
                if (temp[0].Equals("User"))
                {
                    string[] temp2 = sb.ToString().Substring(0, sb.ToString().Length - 1).Split(';');
                    if (temp2[temp2.Length - 1] == "")
                    {
                        output = edm.CreateUserAndMailbox(sb.ToString().Substring(0, sb.ToString().Length - 1), false);
                        SendMail(CISExchangeDaemon.Settings["FromMail"] as string, CISExchangeDaemon.Settings["ExchangeAdminMail"] as string, "Zalozono konto bez hasla dla " + temp[0], "Konto zalozone ale nalezy ustawic haslo recznie", false);
                        SendMail(CISExchangeDaemon.Settings["FromMail"] as string, CISExchangeDaemon.Settings["CISMail"] as string, "Zalozono konto bez hasla dla " + temp[0], "Konto zalozone ale haslo zostanie zalozone recznie. Nalezy skontaktowac sie z administratorem domeny ipj.gov.pl", false);
                    }
                    else
                    {
                        output = edm.CreateUserAndMailbox(sb.ToString().Substring(0, sb.ToString().Length - 1), true);
                    }
                }
                else
                {
                    output = edm.CreateContact(sb.ToString().Substring(0, sb.ToString().Length - 1));
                }
                mail += "===================================\n";
                mail += person + "\n";
                mail += output + "\n";
                string new_file = (file.Split('\\'))[file.Split('\\').Length - 1];
                try
                {
                    File.Move(file, Directory.GetCurrentDirectory() + "\\arch\\" + new_file);
                    Manager.UpdateIndex();
                }
                catch
                {
                    Manager.UpdateIndex();
                }   
            }
            if (mail != null)
            {
                SendMail(CISExchangeDaemon.Settings["FromMail"] as string, CISExchangeDaemon.Settings["CISMail"] as string, "Decyzje dotyczace kont Exchange", mail, false);
                SendMail(CISExchangeDaemon.Settings["FromMail"] as string, CISExchangeDaemon.Settings["ExchangeAdminMail"] as string, "Decyzje dotyczace kont Exchange", mail, false);
            }
            else
            {
                SendMail(CISExchangeDaemon.Settings["FromMail"] as string, CISExchangeDaemon.Settings["CISMail"] as string, "Decyzje dotyczace kont Exchange", "Wystapil blad i utracono dane odnosnie akceptacji kont. Skontaktuj sie z administratorem serwera Exchange", false);
                SendMail(CISExchangeDaemon.Settings["FromMail"] as string, CISExchangeDaemon.Settings["ExchangeAdminMail"] as string, "Blad Exchange Daemon", "Wystapil blad przy wczytywaniu pliku z mailem. NST nie otrzymalo informacji o akceptacji kont", false);
            }
        }
        
        private static string CompareLists(IList<string> before, IList<string> after)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("WIADOMOSC WYGENEROWANA AUTOMATYCZNIE\n");
            sb.Append("=================++++++++++=================\n");
            for (int i = 0; i < before.Count; i++)
            {
                if ((before[i].Split(';'))[0].Equals("add"))
                {
                    sb.Append("Zalozono konto dla uzytkownika " + (before[i].Split(';'))[2] + "\n");
                    if (before[i].Replace(";", "").Equals(after[i].Replace(";", "")))
                    {
                        sb.Append("Dane nie ulegly zmianie\n");
                    }
                    else
                    {
                        sb.Append("Dane zmieniono:\n");
                        string[] before_temp = before[i].Split(';');
                        string[] after_temp = after[i].Split(';');
                        for (int j = 0; j < before_temp.Length; j++)
                        {
                            if (!before_temp[j].Equals(after_temp[j]))
                            {
                                sb.Append(before_temp[j] + " na " + after_temp[j] + "\n");
                            }
                        }
                    }
                    sb.Append("++++++++++++++++++++++++++++++++++++\n");
                }
                else
                {
                    sb.Append("Usunieto konto uzytkownika " + (before[i].Split(';'))[1] + "\n");
                    sb.Append("++++++++++++++++++++++++++++++++++++\n");
                }
            }
            return sb.ToString();
        }

        private static string LoadMail(string filename)
        {
            FileStream fs;
            StreamReader sr;
            try
            {
                fs = File.Open(Directory.GetCurrentDirectory() + "\\" + filename, FileMode.Open);
                sr = new StreamReader(fs);
                string result = sr.ReadToEnd();
                sr.Close();
                fs.Close();
                File.Delete(Directory.GetCurrentDirectory() + "\\" + filename);
                return result;
            }
            catch
            {
                return null;
            }
        }
        
        private static void SendMail(string fromEmail, string toEmail, string subject, string body, bool editable)
        {
            SmtpClient MyMail = new SmtpClient("127.0.0.1");
            MyMail.DeliveryMethod = SmtpDeliveryMethod.Network;
            MyMail.Send(fromEmail, toEmail, subject, body);
        }
    }
}